var oCache = {
        iCacheLower: -1
};

function fnSetKey(aoData, sKey, mValue) {
        for (var i=0, iLen=aoData.length ; i<iLen ; i++) {
                if (aoData[i].name == sKey) {
                        aoData[i].value = mValue;
                }
        }
}

function fnGetKey(aoData, sKey) {
        for (var i=0, iLen=aoData.length ; i<iLen ; i++) {
                if (aoData[i].name == sKey) {
                        return aoData[i].value;
                }
        }
        return null;
}

function oCallbackError(XMLHttpRequest, textStatus, errorThrown) {
        $('.dataTables_processing').css('visibility', 'hidden');
        alert(errorThrown);
}

function fnDataTablesPipeline (sSource, aoData, fnCallback) {
        var iPipe = 5; /* Ajust the pipe size */
        
        var bNeedServer = false;
        var sEcho = fnGetKey(aoData, "sEcho");
        var iRequestStart = fnGetKey(aoData, "iDisplayStart");
        var iRequestLength = fnGetKey(aoData, "iDisplayLength");
        var iRequestEnd = iRequestStart + iRequestLength;
        oCache.iDisplayStart = iRequestStart;
        
        /* outside pipeline? */
        if (oCache.iCacheLower < 0 || iRequestStart < oCache.iCacheLower || iRequestEnd > oCache.iCacheUpper) {
                bNeedServer = true;
        }
        
        /* sorting etc changed? */
        if (oCache.lastRequest && !bNeedServer) {
                for(var i=0, iLen=aoData.length ; i<iLen ; i++) {
                        if (aoData[i].name != "iDisplayStart" && aoData[i].name != "iDisplayLength" && aoData[i].name != "sEcho") {
                                if (aoData[i].value != oCache.lastRequest[i].value)
                                {
                                        bNeedServer = true;
                                        break;
                                }
                        }
                }
        }
        
        /* Store the request for checking next time around */
        oCache.lastRequest = aoData.slice();
        
        if (bNeedServer) {
                if (iRequestStart < oCache.iCacheLower) {
                        iRequestStart = iRequestStart - (iRequestLength*(iPipe-1));
                        if (iRequestStart < 0) {
                                iRequestStart = 0;
                        }
                }
                
                oCache.iCacheLower = iRequestStart;
                oCache.iCacheUpper = iRequestStart + (iRequestLength * iPipe);
                oCache.iDisplayLength = fnGetKey(aoData, "iDisplayLength");
                fnSetKey(aoData, "iDisplayStart", iRequestStart);
                fnSetKey(aoData, "iDisplayLength", iRequestLength*iPipe);
                
                $.ajax({
                        async: true, 
                        cache: true, 
                        url: sSource,
                        dataType: 'json',
                        data: aoData,
                        success: function(json) {
                                oCache.lastJson = jQuery.extend(true, {}, json);
                        
                                if (oCache.iCacheLower != oCache.iDisplayStart) {
                                        json.aaData.splice(0, oCache.iDisplayStart-oCache.iCacheLower);
                                }
                                json.aaData.splice(oCache.iDisplayLength, json.aaData.length);
                                
                                fnCallback(json);
                        }, 
                        error: oCallbackError
                });
                
                /*$.getJSON(sSource, aoData, function (json) { 
                        /; Callback processing
                        oCache.lastJson = jQuery.extend(true, {}, json);
                        
                        if (oCache.iCacheLower != oCache.iDisplayStart) {
                                json.aaData.splice(0, oCache.iDisplayStart-oCache.iCacheLower);
                        }
                        json.aaData.splice(oCache.iDisplayLength, json.aaData.length);
                        
                        fnCallback(json);
                });*/
        }
        else {
                json = jQuery.extend(true, {}, oCache.lastJson);
                json.sEcho = sEcho; /* Update the echo for each response */
                json.aaData.splice(0, iRequestStart-oCache.iCacheLower);
                json.aaData.splice(iRequestLength, json.aaData.length);
                fnCallback(json);
                return;
        }
}